#pragma once

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

extern float PI;

/**
 * @brief 边
 * 
 */
struct Edge
{
    Point up_point;
    Point down_point;
    Point center; // 记录中点是为了便于之后按x坐标排序
};

class ArmorDetector
{
private:
    /* data */

    String video_path;
    double thresh;      // 光条提取阈值
    Scalar line_color;  // 绘制线条颜色
    Scalar point_color; // 绘制点颜色

    float upper_light_ratio; // 灯条长宽比上限
    float lower_light_ratio; // 灯条长宽比下限
    float upper_light_area;  // 灯条面积上限
    float lower_light_area;  // 灯条面积下限

    float upper_armor_ratio; // 甲板长宽上限
    float lower_armor_ratio; // 甲板长宽下限

    int delay; // Cap每帧延迟

    Mat src; // 每帧视频源

    vector<Mat> channels;
    Mat r_channel;                  // 红色通道
    Mat threshold_mask;             //  阈值化结果
    vector<vector<Point>> contours; // 轮廓集合
    vector<Vec4i> hierarchy;        // 轮廓层级关系记录表

public:
    ArmorDetector(String config_path);
    void run();
    ~ArmorDetector() = default;

private:
    inline float getDistance(const Point &a, const Point &b) { return sqrtf((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }
    bool judgeArmor(const Edge &a, const Edge &b, const float upper_limit, const float lower_limit);
    inline Point2f getArmorCenter(const Point2f &a, const Point2f &b, const Point2f &c, const Point2f &d)
    {
        // TL -> BR
        float k1 = (a.y - d.y) / (a.x - d.x);
        // TR -> BL
        float k2 = (b.y - c.y) / (b.x - c.x);
        return Point2f((k1 * a.x - k2 * b.x + b.y - a.y) / (k1 - k2), (k2 * a.y - k1 * b.y + k1 * k2 * (b.x - a.x)) / (k2 - k1));
    }
    void drawArmor(const Mat &out, const Edge &a, const Edge &b, Scalar line_color, Scalar point_color);
    inline Point2f getSpecificPoint(const Point2f center, const float angle, const float distance) { return Point2f(center.x + sinf(angle * PI / 180) * distance, center.y - cosf(angle * PI / 180) * distance); };
};
